package jesss.commands;

import com.amazonaws.services.s3.model.S3Object;
import jesss.options.ExtendedGnuParser;
import jesss.options.JesssOptions;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.MissingArgumentException;
import org.apache.commons.cli.Options;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * User: Lee
 * Date: 9/20/13
 * Time: 8:50 PM
 */
public class SearchForStringInObjectCommand extends AbstractJesssCommand {


    public static final String TEXT_CONTENTTYPE = ".*text.*";
    public static final String OCTET_STREAM_CONTENTTYPE = ".*octet-stream";
    private JesssOptions jesssOptions = null;
    private Options options = new Options();
    private String bucketName;
    private String key;
    private String searchString;
    private boolean ignoreErrorForNonTextFiles = false;

    public SearchForStringInObjectCommand(JesssOptions jesssOptions) throws Exception {
        this.jesssOptions = jesssOptions;
        setOptions();
        try {
            parseArgs(jesssOptions.getArgs());
        } catch (Exception e) {
            printUsage();
            throw e;
        }
    }

    @Override
    public CommandResult executeCommand() {
        CommandResult commandResult = new CommandResult();
        BufferedReader bufferedReader = null;

        displayMessage(String.format("BucketName:%s, Key:%s, SearchString:%s%n", bucketName, key, searchString));

        try {
            S3Object s3Object = jesssOptions.getAmazonS3().getObject(bucketName, key);

            if (checkForSearchableContentType(s3Object)) {
                Pattern pattern = Pattern.compile(searchString);
                bufferedReader = new BufferedReader(new InputStreamReader(s3Object.getObjectContent()));
                String line;

                while ((line = bufferedReader.readLine()) != null) {
                    Matcher matcher = pattern.matcher(line);

                    if (matcher.find()) {
                        System.out.printf("%s/%s: %s%n", bucketName, key, line);
                    }
                }
            } else if (!ignoreErrorForNonTextFiles) {
                throw new Exception(String.format("Unable to search for strings in content type of \"%s\".", s3Object.getObjectMetadata().getContentType()));
            }

            commandResult.setResultStatus(ResultStatus.Success);

        } catch (Exception e) {
            commandResult.setResultStatus(ResultStatus.Error);
            commandResult.setStatusMessage(String.format("Unable to search object \"%s/%s\".",bucketName, key));
            addExceptionInfoToCommandResult(commandResult, e);
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) { }
            }
        }

        return commandResult;
    }

    private boolean checkForSearchableContentType(S3Object s3Object) {
        return s3Object.getObjectMetadata().getContentType().toLowerCase().matches(TEXT_CONTENTTYPE) ||
            s3Object.getObjectMetadata().getContentType().toLowerCase().matches(OCTET_STREAM_CONTENTTYPE);
    }

    private void setOptions() {
        options = new Options();
        options.addOption("bn", "bucketName", true, "Bucket name to list objects from");
        options.addOption("k", "key", true, "Key");
        options.addOption("s", "searchString", true, "Search string (regular expression)");
        options.addOption("ie", "ignoreError", false, "Don't return error when key refers to non-text file.");
    }

    private void parseArgs(String[] args) throws Exception {
        if (args == null || args.length == 0) {
            printUsage();
        }

        try {
            CommandLineParser parser = new ExtendedGnuParser(true);
            CommandLine cmd = parser.parse(options, args);

            if (cmd.hasOption("bn")) {
                bucketName = cmd.getOptionValue("bn");
            } else {
                throw new MissingArgumentException("Missing bucket name parameter.");
            }

            if (cmd.hasOption("k")) {
                key = cmd.getOptionValue("k");
            } else {
                throw new MissingArgumentException("Missing key parameter.");
            }

            if (cmd.hasOption("s")) {
                searchString = cmd.getOptionValue("s");
            } else {
                throw new MissingArgumentException("Missing search string parameter.");
            }

            if (cmd.hasOption("ie")) {
                ignoreErrorForNonTextFiles = true;
            }
        } catch (Exception e) {
            printUsage();
            throw e;
        }
    }

    private void printUsage() {
        System.out.println("Usage:");
        System.out.println("jesss.jesss -cn searchObject -bn <mybucket> -k <key> -s <regular expression search string> [-ie]");
    }
}
